// a sum type instance can hold a value of several different types
struct Moon {}
struct Mars {}
struct Venus {}

// use `type` keyword to declare a sum type
type World = Mars | Moon | Venus

fn (m Mars) dust_storm() bool {
	return true
}

fn (m Moon) moon_walk() {}
fn (m Mars) shiver() {}
fn (v Venus) sweat() {}

// use `match` to determine the variant
fn pass_time(w World) {
    match w {
        // using the shadowed match variable, in this case `w` (smart cast)
        Moon { w.moon_walk() }
        Mars { w.shiver() }
        else {}
    }
}

sum := World(Moon{})
// built-in method `type_name` returns the name of the currently held type
assert sum.type_name() == 'Moon'
println(sum)

// dynamic casts
mut w := World(Moon{})
// check wherther a sum type instance holds a certain type
assert w is Moon
w = Mars{}
// cast a sum type to one of its variants
mars := w as Mars
if mars.dust_storm() {
	println('bad weather!')
}

// smart casting
// flow-sensitive typing
// `w` is a mutable identifier, you have to declare a `mut` before `is`
if mut w is Mars {
	// w has type Mars inside the body of the if statement
	assert typeof(w).name == 'Mars'
	if w.dust_storm() {
		println('bad weather!')
	}
}
